import inspect
from fastapi import Form, Query
from pydantic import BaseModel
from pydantic.fields import FieldInfo
from typing import Type


def as_query(cls: Type[BaseModel]):
    """
    pydantic模型查询参数装饰器，将pydantic模型用于接收查询参数
    此装饰器函数的作用是将一个pydantic模型类转换为一个能够接受查询参数的函数，
    以便在web框架中更容易地处理HTTP请求中的查询参数。

    参数:
    - cls: Type[BaseModel] 要转换为查询参数处理器的pydantic模型类

    返回:
    - Type[BaseModel] 经过转换，增加了查询参数处理功能的模型类
    """
    # 初始化一个新的参数列表，用于存储转换后的查询参数
    new_parameters = []

    # 遍历模型类的字段，将每个字段转换为查询参数
    for field_name, model_field in cls.model_fields.items():
        # 忽略类型警告，因为model_field的确切类型在运行时才能确定
        model_field: FieldInfo  # type: ignore

        # 根据字段是否是必需的，来决定查询参数是否应该有默认值
        if not model_field.is_required():
            # 如果字段不是必需的，为其创建一个带有默认值的查询参数
            new_parameters.append(
                inspect.Parameter(
                    model_field.alias,
                    inspect.Parameter.POSITIONAL_ONLY,
                    default=Query(default=model_field.default, description=model_field.description),
                    annotation=model_field.annotation,
                )
            )
        else:
            # 如果字段是必需的，为其创建一个没有默认值的查询参数
            new_parameters.append(
                inspect.Parameter(
                    model_field.alias,
                    inspect.Parameter.POSITIONAL_ONLY,
                    default=Query(..., description=model_field.description),
                    annotation=model_field.annotation,
                )
            )

    # 定义一个新的函数，该函数将使用之前创建的查询参数
    async def as_query_func(**data):
        # 使用传入的数据创建并返回模型类的实例
        return cls(**data)

    # 获取新函数的签名，并用新参数替换其参数列表
    sig = inspect.signature(as_query_func)
    sig = sig.replace(parameters=new_parameters)
    # 将修改后的签名附加到新函数上
    as_query_func.__signature__ = sig  # type: ignore
    # 将新函数作为属性附加到模型类上
    setattr(cls, 'as_query', as_query_func)
    # 返回经过修改的模型类
    return cls



def as_form(cls: Type[BaseModel]):
    """
    pydantic模型表单参数装饰器，将pydantic模型用于接收表单参数
    """
    new_parameters = []

    for field_name, model_field in cls.model_fields.items():
        model_field: FieldInfo  # type: ignore

        if not model_field.is_required():
            new_parameters.append(
                inspect.Parameter(
                    model_field.alias,
                    inspect.Parameter.POSITIONAL_ONLY,
                    default=Form(default=model_field.default, description=model_field.description),
                    annotation=model_field.annotation,
                )
            )
        else:
            new_parameters.append(
                inspect.Parameter(
                    model_field.alias,
                    inspect.Parameter.POSITIONAL_ONLY,
                    default=Form(..., description=model_field.description),
                    annotation=model_field.annotation,
                )
            )

    async def as_form_func(**data):
        return cls(**data)

    sig = inspect.signature(as_form_func)
    sig = sig.replace(parameters=new_parameters)
    as_form_func.__signature__ = sig  # type: ignore
    setattr(cls, 'as_form', as_form_func)
    return cls
